MeUtils 2025.8.27.12.25.12__py3-none-any.whl → 2025.8.29.16.39.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : open_router
5
+ # @Time : 2024/10/14 19:04
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
12
+ from openai import OpenAI
13
+ from os import getenv
14
+ from meutils.io.files_utils import to_url
15
+
16
+ # gets API Key from environment variable OPENAI_API_KEY
17
+ client = OpenAI(
18
+ # base_url="https://openrouter.ai/api/v1",
19
+ # base_url="https://all.chatfire.cn/openrouter/v1",
20
+ # api_key=os.getenv("OPENROUTER_API_KEY"),
21
+ #
22
+ # base_url="http://38.46.219.252:9001/v1",
23
+ #
24
+ # api_key="sk-Azgp1thTIonR7IdIEqlJU51tpDYNIYYpxHvAZwFeJiOdVWiz"
25
+
26
+ base_url="https://api.huandutech.com/v1",
27
+ api_key = "sk-qOpbMHesasoVgX75ZoeEeBEf1R9dmsUZVAPcu5KkvLFhElrn"
28
+ )
29
+
30
+ completion = client.chat.completions.create(
31
+ # extra_headers={
32
+ # "HTTP-Referer": $YOUR_SITE_URL, # Optional, for including your app on openrouter.ai rankings.
33
+ # "X-Title": $YOUR_APP_NAME, # Optional. Shows in rankings on openrouter.ai.
34
+ # },
35
+ # model="meta-llama/llama-3.2-11b-vision-instruct:free",
36
+ # model="openai/o1",
37
+ # model="deepseek/deepseek-r1-0528-qwen3-8b:free",
38
+ # model="google/gemini-2.5-flash-image-preview:free",
39
+ model="gemini-2.5-flash-image-preview",
40
+ # model="gemini-2.0-flash-exp-image-generation",
41
+ # max_tokens=10,
42
+
43
+ messages=[
44
+ {
45
+ "role": "user",
46
+ "content": [
47
+ {
48
+ "type": "text",
49
+ "text": "带个墨镜"
50
+ },
51
+ {
52
+ "type": "image_url",
53
+ "image_url": {
54
+ "url": "https://oss.ffire.cc/files/kling_watermark.png"
55
+ }
56
+ }
57
+ ]
58
+ }
59
+ ]
60
+ )
61
+ # print(completion.choices[0].message.content)
62
+ # arun(to_url(completion.choices[0].message.images[0]['image_url']['url'], content_type="image/png"))
63
+
64
+
65
+ # arun(to_url(completion.choices[0].message.images[0]['image_url']['url'], content_type="image/png"))
66
+
67
+ # print(dict(completion.choices[0].message).keys())
68
+
69
+ # {
70
+ # "index": 0,
71
+ # "type": "image_url",
72
+ # "image_url": {
73
+ # "url": "b64"
74
+ # }
75
+ #
76
+ # }
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : 异步
5
+ # @Time : 2025/8/28 15:29
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
12
+
13
+
14
+ async def f():
15
+ 1/0
16
+
17
+
18
+
19
+ async def main():
20
+ future_task = asyncio.create_task(f()) # 异步执行
21
+ # future_task.exception()
22
+
23
+ try:
24
+ await future_task
25
+ except Exception as e:
26
+ raise e
27
+ # print(e)
28
+ # print(future_task.exception())
29
+
30
+
31
+ if __name__ == '__main__':
32
+ asyncio.run(main())
@@ -109,15 +109,15 @@ async def generate(request: ImageRequest, n: int = 30): # 兼容dalle3
109
109
 
110
110
  # VideoResult
111
111
  if __name__ == '__main__':
112
- api_key = "8c1fd8923a2f4c0eb323335ca4ba9f98.I7FisfQS7x1zYK8P"
112
+ api_key = "c98aa404b0224690b211c5d1e420db2c.qGaByuJATne08QUx"
113
113
 
114
114
  # api_key = "c98aa404b0224690b211c5d1e420db2c.qGaByuJATne08QUx"
115
115
  # api_key = "7d10426c06afa81e8d7401d97781249c.DbqlSsicRtaUdKXI" # 新号
116
116
  # api_key = "e21bd630f681c4d90b390cd609720483.WSFVgA3Kk1wNCX0mN"
117
117
 
118
118
  request = VideoRequest(
119
- model='cogvideox-flash',
120
- # model='cogvideox-3',
119
+ # model='cogvideox-flash',
120
+ model='cogvideox-3',
121
121
 
122
122
  )
123
123
  r = arun(create_task(request, api_key=api_key))
@@ -204,6 +204,7 @@ async def generate(request: ImageRequest, api_key: Optional[str] = None):
204
204
  "prompt": request.prompt,
205
205
  "image_urls": request.image_urls,
206
206
  "num_images": request.n or 1,
207
+ "output_format": "png"
207
208
  }
208
209
  if request.image_urls:
209
210
  request.model = f"""{request.model.removesuffix("/edit")}/edit"""
@@ -67,6 +67,9 @@ class Completions(object):
67
67
  self.base_url = base_url or "https://all.chatfire.cc/genai"
68
68
  self.client = None ####
69
69
 
70
+ if self.base_url.endswith("/v1"):
71
+ self.base_url = self.base_url.removesuffix('/v1')
72
+
70
73
  async def create_for_search(self, request: CompletionRequest):
71
74
  self.client = self.client or await self.get_client()
72
75
 
@@ -189,14 +192,18 @@ class Completions(object):
189
192
  yield e
190
193
  raise e
191
194
 
192
- @retrying(title=__name__)
195
+ @retrying(max_retries=3, title=__name__)
193
196
  async def generate(self, request: ImageRequest): # OpenaiD3
194
- request.model = "gemini-2.0-flash-exp-image-generation"
195
- image, prompt = request.image_and_prompt
196
- parts = [Part.from_text(text=prompt)]
197
- if image:
198
- data = await to_bytes(image)
199
- parts.append(Part.from_bytes(data=data, mime_type="image/png"))
197
+ image_urls = request.image_urls
198
+
199
+ logger.debug(request.prompt)
200
+ logger.debug(request.image_urls)
201
+
202
+ parts = [Part.from_text(text=request.prompt)]
203
+ if image_urls:
204
+ _ = await asyncio.gather(*[to_bytes(image_url) for image_url in image_urls])
205
+ for data in _:
206
+ parts.append(Part.from_bytes(data=data, mime_type="image/png"))
200
207
 
201
208
  self.client = self.client or await self.get_client()
202
209
  chat = self.client.aio.chats.create(
@@ -212,13 +219,19 @@ class Completions(object):
212
219
  parts = response.candidates[0].content.parts or []
213
220
  for part in parts:
214
221
  if part.inline_data:
215
- image_url = await to_url(part.inline_data.data, mime_type=part.inline_data.mime_type)
216
- image_response.data.append({"url": image_url, "revised_prompt": part.text})
222
+ if request.response_format == "b64_json":
223
+ url = part.inline_data.data
224
+ else:
225
+ url = await to_url(part.inline_data.data, mime_type=part.inline_data.mime_type)
226
+
227
+ image_response.data.append({"url": url, "revised_prompt": part.text})
217
228
 
218
- return image_response
229
+ if image_response.data:
230
+ return image_response
231
+ else:
232
+ raise Exception(f"image generate failed: {image_response}")
219
233
 
220
234
  async def create_for_images(self, request: CompletionRequest):
221
- request.model = "gemini-2.0-flash-exp-image-generation" ####### 目前是强行
222
235
 
223
236
  messages = await self.to_image_messages(request)
224
237
 
@@ -253,7 +266,7 @@ class Completions(object):
253
266
  if chunk.candidates and chunk.candidates[0].content:
254
267
  parts = chunk.candidates[0].content.parts or []
255
268
  for part in parts:
256
- # logger.debug(part)
269
+ logger.debug(part)
257
270
  if part.text:
258
271
  yield part.text
259
272
 
@@ -419,38 +432,52 @@ if __name__ == '__main__':
419
432
 
420
433
  # content = "https://oss.ffire.cc/files/nsfw.jpg 移除右下角的水印"
421
434
 
422
-
423
435
  messages = [
424
- {
425
- "role": "system",
426
- "content": "你是一位极其严谨的短剧剧本分析师和转写专家。你的核心原则是【在绝对尊重视频内容的前提下,解决上下文矛盾】。视频是唯一的“事实源”,上下文是“校准器”,你必须用校准器来修正你对事实源的解读。\n\n你的工作流程分为两个层级:【首要任务:基于上下文的视频重审策略】和【基础任务:高质量转写与格式化】。\n\n----------------------------------------------------------------------\n【一、首要任务:基于上下文的视频重审策略】\n当你收到【特别注意】的错误提示时,这并非让你脱离视频创作,而是表明你上一次对视频的“理解”可能存在偏差。你必须执行以下重审策略:\n\n- 若提示【角色名/身份错误】:这表明你对角色的姓名或身份识别有误。请基于上下文提供的正确信息(例如,正确的名字是“苏沫”而不是“苏沐”),在当前及后续的所有转写中,统一修正该角色的所有称呼。这不仅是简单的“查找替换”,而是要将正确的身份认知贯彻到整个剧本中。\n- 若提示【情节倒置】:这通常意味着你对视频中的【胜负关系】或【权力动态】产生了误判。请重新审视视频画面,特别是人物的表情、动作和位置,生成一个符合上下文逻辑的、对视频的正确解读。例如,如果提示“主角上一集结尾占上风,本集开头却被殴打”,请你重新仔细看视频,找出主角反击或压制对手的画面,并据此转写。\n- 若提示【角色/情节丢失】:这表明你可能在视频中忽略了某个关键人物或事件。请重新仔细观看视频,像侦探一样去找到那位被上下文证明“应该在场”的角色,并将其在视频中的实际行为和对话补充到剧本中。\n- 若提示【事实性硬伤】(如道具矛盾):请重新检查视频中的相关物体或状态。如果视频本身存在矛盾(例如,由于拍摄失误导致的道具不连戏),你可以选择最合理的一种状态进行描述,或者在场景描述中用一句话合乎情理地解释这个变化(例如:△他从口袋里拿出另一个一模一样的玉佩)。这依然是基于视频画面的创作,而非凭空捏造。\n\n总而言之:你不是在编故事,你是在纠正你自己的“看错了”的问题。 所有的修正,都必须能在视频画面中找到依据。\n----------------------------------------------------------------------\n\n【二、基础任务:高质量转写与格式化准则】\n在完成内容重审和转写后,你的输出必须严格、无条件地遵循以下所有规则。这是一个绝对的格式要求。\n\n【格式总则】\n1. 语言:必须使用简体中文。\n2. 纯净度:剧本全文严禁出现\"*\"、\"【】\"(除格式要求外)、\"(说明:...)\"等任何多余符号和文字。严禁出现“场景描述:”、“动作描述:”等提示词。\n3. *禁止项*:严禁描述人物的妆容、穿衣打扮。严禁使用“字幕:....”来提示台词,台词必须由具体角色说出。\n4. *精炼性*:严格检测并删除任何重复或无意义的台词和动作。\n\n*【剧本结构与内容规则】*\n1. *场次标题: 集数序号-场次序号 地点(主场景+次场景) 日或夜 内或外\n 集数序号:本视频对应的集数。\n * *场次序号*:必须以*集为单位,从1开始连续编号(如1-1, 1-2... 2-1, 2-2...)。\n 地点:必须具体,包含主场景和次场景(如“容宅 走廊”、“医院 病房”)。严禁使用“室内”或“卧室”等模糊或孤立的描述。\n * *场景划分*:仅在时间、地点或核心情节发生明确切换时才划分新场次。同一时空内的连续对话或细微背景变化*不*划分新场次。\n\n2. *出场人物: 出场人物:人物A、人物B、人物C\n 每场戏开始时,必须列出本场所有出场的角色。\n * 角色名在全剧中必须保持一致。不确定时用描述性称呼(如“青年男子”),但要求你尽量参考大纲和角色清单,分辨出角色名字。\n\n3. *场景描述*: 直接进行文字描述,描述布景、核心道具、环境氛围。\n\n4. *动作描述: △[动作描述]\n 必须以△符号起始。人物台词前严禁加△。\n * 同一角色的连续动作写在同一行,不同角色的动作必须另起新行并以△开头。\n\n5. *对白: 角色名(情感或动作提示):对白内容。\n 情感提示(如“愤怒地”、“冷笑”)必须放在括号内。\n\n6. 旁白:\n 内心独白: 角色名(OS):内容\n 画外音: (VO):内容\n\n【剧本格式示例(仅供学习格式,内容不要模仿)】\n正确格式:\n4-1 高铁车厢 日 内\n出场人物:周愿、苏美兰、熊天赐、乘客甲、乘客乙\n场景描述:\n高铁车厢内,乘客们各自休息。周愿坐在座位上,看着窗外,神情低落。苏美兰母子坐在周愿的对面,熊天赐在玩平板电脑。\n△苏美兰得意地看着周愿。\n苏美兰(挑衅地):你还吹什么牛啊?还刚从精神病院放出来?哎,你浑身上下,哪一点像精神病啊?竟然还敢吓唬我,今天我非扒你一层皮!\n△苏美兰突然起身,伸手去抓周愿的头发。\n周愿(惊叫):啊!\n△周愿挣扎着躲避。\n苏美兰:你干什么?\n△苏美兰用力撕扯周愿的头发。\n\n【核心逻辑:场次合并规则】\n* *强制合并*: 在处理单集时,只要*相邻的场次标题完全相同,就【必须】无条件地合并为一个场次。\n 合并内容: 合并后的场次,其“出场人物”列表必须是所有被合并场次人物的并集,其下的所有场景、动作、对话描述需按时间顺序整合。\n* 禁止“同场次”: 严禁出现“同场次”或任何类似的过渡性描述,直接合并。\n\n【!!!绝对规则!!!】\n任务结束时,立即停止输出。不要添加任何形式的总结、确认、祝福语或收尾性评论,如“好的”、“剧本已生成”等。直接输出剧本本身。\n"
427
- },
428
- {
429
- "role": "user",
430
- "content": [
431
- {
432
- "text": "【特别注意】\n前一版剧本因 '从生成阶段加载的脚本为空,需要首次生成' 被系统否决。\n请在本次生成中,基于视频内容,着重解决此问题。\n\n### 全局故事大纲与角色清单 (重要参考) ###\n好的,我已经仔细阅读并分析了您提供的剧本。以下是根据您的要求生成的【故事大纲】和【角色清单】。\n\n### 故事大纲 ###\n故事围绕着中国航天事业的巨大成功和一个家庭的温馨团聚展开。开篇,一位名叫苏念的女性独自在书房,激动地看着卫星发射成功的直播。她对着夜空,向一位名叫“斯年”的故人倾诉,感叹他们当年的梦想——让中国的卫星布满星空——终于实现,将宏大的国家叙事与深厚的个人情感联系在一起。\n\n情节随即转换到苏家大宅,这里的气氛同样热烈。大家长苏老和儿孙们正欢欣鼓舞地庆祝着同一场卫星发射的成功,并准备拍摄一张全家福来纪念这个特殊的日子。正当一切准备就绪时,一个穿着军装的身影——苏老的三儿子——在最后一刻赶回了家中。他的归来为这个喜庆的场面增添了团圆的圆满。苏念也来到大厅,为家庭的完整而欣喜。最终,摄影师按下了快门,将这个融合了国家荣耀与家庭幸福的瞬间定格为永恒,故事在温馨、自豪的氛围中结束。\n\n### 角色清单 ###\n- 角色名 (标准): 苏念\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 故事的情感核心人物,苏家的女主人。\n 核心特点: 感性、深情,心系国家航天事业与家庭。\n 关系: 与“斯年”有着共同的理想;是苏家的核心成员,可能是苏老的妻子。\n\n- 角色名 (标准): 苏老\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的大家长,行动需依靠轮椅。\n 核心特点: 和蔼可亲,重视家庭团聚。\n 关系: 苏家的最高长辈,“老三”等人的父亲。\n\n- 角色名 (标准): 老三\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏老的第三个儿子,一名现役军官。\n 核心特点: 气质干练,富有家庭责任感。\n 关系: 苏老的儿子;青年男子某乙的“三弟”。\n\n- 角色名 (标准): 斯年\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 一位在回忆中被提及的人物,并未出场。\n 核心特点: 怀有航天梦想。\n 关系: 与苏念关系极为亲密,共同拥有一个关于星辰大海的愿望,推测是其已故的伴侣或亲人。\n\n- 角色名 (标准): 青年男子某乙\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 性格开朗,为弟弟的归来和家庭团聚感到兴奋。\n 关系: 苏老的子辈,“老三”的兄长。\n\n- 角色名 (标准): 青年男子某甲\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 积极参与家庭活动。\n 关系: 苏老的子辈或孙辈。\n\n- 角色名 (标准): 青年男子某丙\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 积极参与家庭活动。\n 关系: 苏老的子辈或孙辈。\n\n- 角色名 (标准): 青年男子某丁\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 乐于用手机记录和分享喜悦。\n 关系: 苏老的子辈或孙辈。\n\n- 角色名 (标准): 小女孩\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的孙辈成员。\n 核心特点: 天真活泼。\n 关系: 苏老的孙辈。\n\n- 角色名 (标准): 摄影师\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 被邀请来为苏家拍摄全家福的专业人士。\n 核心特点: 专业,注重细节。\n 关系: 无。\n---------------------------------\n\n现在,请根据以上所有信息和提供的视频,为系列剧的 第 18 集 创作剧本。\n\n--- 上下文参考 ---\n前一集结尾内容:\n---\n无\n---\n\n后一集开头内容:\n---\n无\n---\n-------------------\n",
433
- "type": "text"
434
- },
435
- {
436
- "type": "video_url",
437
- "video_url": {
438
- "url": "https://lmdbk.com/5.mp4"
439
- }
436
+ {
437
+ "role": "system",
438
+ "content": "你是一位极其严谨的短剧剧本分析师和转写专家。你的核心原则是【在绝对尊重视频内容的前提下,解决上下文矛盾】。视频是唯一的“事实源”,上下文是“校准器”,你必须用校准器来修正你对事实源的解读。\n\n你的工作流程分为两个层级:【首要任务:基于上下文的视频重审策略】和【基础任务:高质量转写与格式化】。\n\n----------------------------------------------------------------------\n【一、首要任务:基于上下文的视频重审策略】\n当你收到【特别注意】的错误提示时,这并非让你脱离视频创作,而是表明你上一次对视频的“理解”可能存在偏差。你必须执行以下重审策略:\n\n- 若提示【角色名/身份错误】:这表明你对角色的姓名或身份识别有误。请基于上下文提供的正确信息(例如,正确的名字是“苏沫”而不是“苏沐”),在当前及后续的所有转写中,统一修正该角色的所有称呼。这不仅是简单的“查找替换”,而是要将正确的身份认知贯彻到整个剧本中。\n- 若提示【情节倒置】:这通常意味着你对视频中的【胜负关系】或【权力动态】产生了误判。请重新审视视频画面,特别是人物的表情、动作和位置,生成一个符合上下文逻辑的、对视频的正确解读。例如,如果提示“主角上一集结尾占上风,本集开头却被殴打”,请你重新仔细看视频,找出主角反击或压制对手的画面,并据此转写。\n- 若提示【角色/情节丢失】:这表明你可能在视频中忽略了某个关键人物或事件。请重新仔细观看视频,像侦探一样去找到那位被上下文证明“应该在场”的角色,并将其在视频中的实际行为和对话补充到剧本中。\n- 若提示【事实性硬伤】(如道具矛盾):请重新检查视频中的相关物体或状态。如果视频本身存在矛盾(例如,由于拍摄失误导致的道具不连戏),你可以选择最合理的一种状态进行描述,或者在场景描述中用一句话合乎情理地解释这个变化(例如:△他从口袋里拿出另一个一模一样的玉佩)。这依然是基于视频画面的创作,而非凭空捏造。\n\n总而言之:你不是在编故事,你是在纠正你自己的“看错了”的问题。 所有的修正,都必须能在视频画面中找到依据。\n----------------------------------------------------------------------\n\n【二、基础任务:高质量转写与格式化准则】\n在完成内容重审和转写后,你的输出必须严格、无条件地遵循以下所有规则。这是一个绝对的格式要求。\n\n【格式总则】\n1. 语言:必须使用简体中文。\n2. 纯净度:剧本全文严禁出现\"*\"、\"【】\"(除格式要求外)、\"(说明:...)\"等任何多余符号和文字。严禁出现“场景描述:”、“动作描述:”等提示词。\n3. *禁止项*:严禁描述人物的妆容、穿衣打扮。严禁使用“字幕:....”来提示台词,台词必须由具体角色说出。\n4. *精炼性*:严格检测并删除任何重复或无意义的台词和动作。\n\n*【剧本结构与内容规则】*\n1. *场次标题: 集数序号-场次序号 地点(主场景+次场景) 日或夜 内或外\n 集数序号:本视频对应的集数。\n * *场次序号*:必须以*集为单位,从1开始连续编号(如1-1, 1-2... 2-1, 2-2...)。\n 地点:必须具体,包含主场景和次场景(如“容宅 走廊”、“医院 病房”)。严禁使用“室内”或“卧室”等模糊或孤立的描述。\n * *场景划分*:仅在时间、地点或核心情节发生明确切换时才划分新场次。同一时空内的连续对话或细微背景变化*不*划分新场次。\n\n2. *出场人物: 出场人物:人物A、人物B、人物C\n 每场戏开始时,必须列出本场所有出场的角色。\n * 角色名在全剧中必须保持一致。不确定时用描述性称呼(如“青年男子”),但要求你尽量参考大纲和角色清单,分辨出角色名字。\n\n3. *场景描述*: 直接进行文字描述,描述布景、核心道具、环境氛围。\n\n4. *动作描述: △[动作描述]\n 必须以△符号起始。人物台词前严禁加△。\n * 同一角色的连续动作写在同一行,不同角色的动作必须另起新行并以△开头。\n\n5. *对白: 角色名(情感或动作提示):对白内容。\n 情感提示(如“愤怒地”、“冷笑”)必须放在括号内。\n\n6. 旁白:\n 内心独白: 角色名(OS):内容\n 画外音: (VO):内容\n\n【剧本格式示例(仅供学习格式,内容不要模仿)】\n正确格式:\n4-1 高铁车厢 日 内\n出场人物:周愿、苏美兰、熊天赐、乘客甲、乘客乙\n场景描述:\n高铁车厢内,乘客们各自休息。周愿坐在座位上,看着窗外,神情低落。苏美兰母子坐在周愿的对面,熊天赐在玩平板电脑。\n△苏美兰得意地看着周愿。\n苏美兰(挑衅地):你还吹什么牛啊?还刚从精神病院放出来?哎,你浑身上下,哪一点像精神病啊?竟然还敢吓唬我,今天我非扒你一层皮!\n△苏美兰突然起身,伸手去抓周愿的头发。\n周愿(惊叫):啊!\n△周愿挣扎着躲避。\n苏美兰:你干什么?\n△苏美兰用力撕扯周愿的头发。\n\n【核心逻辑:场次合并规则】\n* *强制合并*: 在处理单集时,只要*相邻的场次标题完全相同,就【必须】无条件地合并为一个场次。\n 合并内容: 合并后的场次,其“出场人物”列表必须是所有被合并场次人物的并集,其下的所有场景、动作、对话描述需按时间顺序整合。\n* 禁止“同场次”: 严禁出现“同场次”或任何类似的过渡性描述,直接合并。\n\n【!!!绝对规则!!!】\n任务结束时,立即停止输出。不要添加任何形式的总结、确认、祝福语或收尾性评论,如“好的”、“剧本已生成”等。直接输出剧本本身。\n"
439
+ },
440
+ {
441
+ "role": "user",
442
+ "content": [
443
+ {
444
+ "text": "【特别注意】\n前一版剧本因 '从生成阶段加载的脚本为空,需要首次生成' 被系统否决。\n请在本次生成中,基于视频内容,着重解决此问题。\n\n### 全局故事大纲与角色清单 (重要参考) ###\n好的,我已经仔细阅读并分析了您提供的剧本。以下是根据您的要求生成的【故事大纲】和【角色清单】。\n\n### 故事大纲 ###\n故事围绕着中国航天事业的巨大成功和一个家庭的温馨团聚展开。开篇,一位名叫苏念的女性独自在书房,激动地看着卫星发射成功的直播。她对着夜空,向一位名叫“斯年”的故人倾诉,感叹他们当年的梦想——让中国的卫星布满星空——终于实现,将宏大的国家叙事与深厚的个人情感联系在一起。\n\n情节随即转换到苏家大宅,这里的气氛同样热烈。大家长苏老和儿孙们正欢欣鼓舞地庆祝着同一场卫星发射的成功,并准备拍摄一张全家福来纪念这个特殊的日子。正当一切准备就绪时,一个穿着军装的身影——苏老的三儿子——在最后一刻赶回了家中。他的归来为这个喜庆的场面增添了团圆的圆满。苏念也来到大厅,为家庭的完整而欣喜。最终,摄影师按下了快门,将这个融合了国家荣耀与家庭幸福的瞬间定格为永恒,故事在温馨、自豪的氛围中结束。\n\n### 角色清单 ###\n- 角色名 (标准): 苏念\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 故事的情感核心人物,苏家的女主人。\n 核心特点: 感性、深情,心系国家航天事业与家庭。\n 关系: 与“斯年”有着共同的理想;是苏家的核心成员,可能是苏老的妻子。\n\n- 角色名 (标准): 苏老\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的大家长,行动需依靠轮椅。\n 核心特点: 和蔼可亲,重视家庭团聚。\n 关系: 苏家的最高长辈,“老三”等人的父亲。\n\n- 角色名 (标准): 老三\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏老的第三个儿子,一名现役军官。\n 核心特点: 气质干练,富有家庭责任感。\n 关系: 苏老的儿子;青年男子某乙的“三弟”。\n\n- 角色名 (标准): 斯年\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 一位在回忆中被提及的人物,并未出场。\n 核心特点: 怀有航天梦想。\n 关系: 与苏念关系极为亲密,共同拥有一个关于星辰大海的愿望,推测是其已故的伴侣或亲人。\n\n- 角色名 (标准): 青年男子某乙\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 性格开朗,为弟弟的归来和家庭团聚感到兴奋。\n 关系: 苏老的子辈,“老三”的兄长。\n\n- 角色名 (标准): 青年男子某甲\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 积极参与家庭活动。\n 关系: 苏老的子辈或孙辈。\n\n- 角色名 (标准): 青年男子某丙\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 积极参与家庭活动。\n 关系: 苏老的子辈或孙辈。\n\n- 角色名 (标准): 青年男子某丁\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的子辈成员。\n 核心特点: 乐于用手机记录和分享喜悦。\n 关系: 苏老的子辈或孙辈。\n\n- 角色名 (标准): 小女孩\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 苏家的孙辈成员。\n 核心特点: 天真活泼。\n 关系: 苏老的孙辈。\n\n- 角色名 (标准): 摄影师\n 别名: 无\n 待修正的错误写法: 无\n 身份/简介: 被邀请来为苏家拍摄全家福的专业人士。\n 核心特点: 专业,注重细节。\n 关系: 无。\n---------------------------------\n\n现在,请根据以上所有信息和提供的视频,为系列剧的 第 18 集 创作剧本。\n\n--- 上下文参考 ---\n前一集结尾内容:\n---\n无\n---\n\n后一集开头内容:\n---\n无\n---\n-------------------\n",
445
+ "type": "text"
446
+ },
447
+ {
448
+ "type": "video_url",
449
+ "video_url": {
450
+ "url": "https://lmdbk.com/5.mp4"
440
451
  }
441
- ]
442
- }
443
- ]
452
+ }
453
+ ]
454
+ }
455
+ ]
456
+
457
+ messages = [
458
+
459
+ {
460
+ "role": "user",
461
+ "content": [
462
+ {
463
+ "text": "画条狗",
464
+ "type": "text"
465
+ },
466
+
467
+ ]
468
+ }
469
+ ]
444
470
 
445
- #
446
471
  request = CompletionRequest(
447
472
  # model="qwen-turbo-2024-11-01",
448
473
  # model="gemini-all",
449
474
  # model="gemini-2.0-flash-exp-image-generation",
450
- model="gemini-2.0-flash",
475
+ # model="gemini-2.0-flash",
451
476
  # model="gemini-2.5-flash-preview-04-17",
452
477
  # model="gemini-2.5-flash-preview-04-17",
453
478
 
479
+ model="gemini-2.5-flash-image-preview",
480
+
454
481
  # messages=[
455
482
  # {
456
483
  # 'role': 'user',
@@ -465,15 +492,37 @@ if __name__ == '__main__':
465
492
 
466
493
  # arun(Completions(api_key=api_key).create_for_search(request))
467
494
 
468
- # arun(Completions(api_key=api_key).create_for_images(request))
469
- arun(Completions().create_for_files(request))
495
+ base_url = "gemini/v1beta/models/{self.model}:generateContent"
496
+
497
+ base_url = "http://38.46.219.252:9001"
498
+ api_key = "sk-Azgp1thTIonR7IdIEqlJU51tpDYNIYYpxHvAZwFeJiOdVWiz"
499
+
500
+ base_url = "https://api.huandutech.com"
501
+ api_key = "sk-qOpbMHesasoVgX75ZoeEeBEf1R9dmsUZVAPcu5KkvLFhElrn"
502
+
503
+ # arun(Completions(base_url=base_url, api_key=api_key).create_for_images(request))
504
+ # arun(Completions(base_url=base_url, api_key=api_key).generate(request))
505
+
506
+ # arun(Completions().create_for_files(request))
470
507
 
471
508
  # arun(Completions(api_key=api_key).create_for_files(request))
472
509
 
473
- # request = ImageRequest(
474
- # prompt="https://oss.ffire.cc/files/nsfw.jpg 移除右下角 白色的水印",
475
- # # prompt="画条可爱的狗",
476
- #
477
- # )
478
- #
479
- # arun(Completions(api_key=api_key).generate(request))
510
+ request = ImageRequest(
511
+ model="gemini-2.5-flash-image-preview",
512
+
513
+ # prompt="https://oss.ffire.cc/files/nsfw.jpg 移除右下角 白色的水印",
514
+ # prompt="画条可爱的狗",
515
+
516
+ # prompt="带个墨镜",
517
+ # image="https://oss.ffire.cc/files/kling_watermark.png",
518
+
519
+ prompt="把小鸭子放在女人的T恤上面",
520
+
521
+ image=[
522
+ "https://v3.fal.media/files/penguin/XoW0qavfF-ahg-jX4BMyL_image.webp",
523
+ "https://v3.fal.media/files/tiger/bml6YA7DWJXOigadvxk75_image.webp"
524
+ ]
525
+
526
+ )
527
+
528
+ arun(Completions(base_url=base_url, api_key=api_key).generate(request))
@@ -7,21 +7,124 @@
7
7
  # @WeChat : meutils
8
8
  # @Software : PyCharm
9
9
  # @Description : D3 生图、编辑图
10
+ """
11
+ # {
12
+ # "index": 0,
13
+ # "type": "image_url",
14
+ # "image_url": {
15
+ # "url": "b64"
16
+ # }
17
+ #
18
+ # }
10
19
 
11
- from meutils.pipe import *
20
+ """
12
21
 
13
- from meutils.apis.google.chat import Completions, CompletionRequest
22
+ from meutils.pipe import *
23
+ from meutils.io.files_utils import to_url
24
+ from meutils.llm.clients import AsyncOpenAI
25
+ from meutils.apis.images.edits import edit_image, ImageProcess
14
26
 
15
- from meutils.schemas.image_types import ImageRequest
27
+ from meutils.schemas.image_types import ImageRequest, ImagesResponse
28
+ from meutils.schemas.openai_types import CompletionRequest
16
29
 
17
30
 
31
+ async def generate(request: ImageRequest, api_key: Optional[str] = None, base_url: Optional[str] = None):
32
+ is_hd = False
33
+ if request.model.endswith("-hd"):
34
+ is_hd = True
35
+ request.model = request.model.removesuffix("-hd")
18
36
 
37
+ image_urls = request.image_urls
38
+ image_urls = await to_url(image_urls, filename='.png', content_type="image/png")
39
+ image_urls = [
40
+ {
41
+ "type": "image_url",
42
+ "image_url": {
43
+ "url": image_url
44
+ }
45
+ }
46
+ for image_url in image_urls or []
47
+ ]
19
48
 
20
- async def generate(request: ImageRequest, api_key: Optional[str] = None):
21
49
  request = CompletionRequest(
22
- model="gemini-2.0-flash-exp-image-generation",
50
+ model=request.model,
51
+ stream=False,
52
+ max_tokens=None,
23
53
  messages=[
24
-
54
+ {
55
+ "role": "user",
56
+ "content": [
57
+ {
58
+ "type": "text",
59
+ "text": request.prompt
60
+ },
61
+ *image_urls
62
+ ]
63
+ }
25
64
  ],
26
65
  )
27
- return Completions().create_for_images(request)
66
+
67
+ data = request.model_dump(exclude_none=True)
68
+
69
+ client = AsyncOpenAI(
70
+ base_url=base_url,
71
+ api_key=api_key
72
+ # base_url="https://openrouter.ai/api/v1",
73
+ # base_url="https://all.chatfire.cn/openrouter/v1",
74
+ # api_key=api_key or os.getenv("OPENROUTER_API_KEY"),
75
+
76
+ )
77
+
78
+ completion = await client.chat.completions.create(**data)
79
+ # logger.debug(completion)
80
+ if (
81
+ completion
82
+ and completion.choices
83
+ and hasattr(completion.choices[0].message, "images")
84
+ and (images := completion.choices[0].message.images)
85
+ ):
86
+ image_urls = [image['image_url']['url'] for image in images]
87
+ # logger.debug(image_urls)
88
+
89
+ if request.response_format == "b64_json":
90
+ response = ImagesResponse(image=image_urls)
91
+
92
+ elif is_hd:
93
+ # logger.debug(image_urls)
94
+ tasks = [edit_image(ImageProcess(model="clarity", image=image_url)) for image_url in image_urls]
95
+ responses = await asyncio.gather(*tasks)
96
+
97
+ image_urls = [dict(response.data[0])["url"] for response in responses if response.data]
98
+ response = ImagesResponse(image=image_urls)
99
+
100
+ else:
101
+ image_urls = await to_url(image_urls, filename='.png', content_type="image/png")
102
+ response = ImagesResponse(image=image_urls)
103
+
104
+ # logger.debug(response)
105
+
106
+ if response.data:
107
+ return response
108
+
109
+ raise Exception(f"image generate failed: {completion}")
110
+
111
+
112
+ if __name__ == '__main__':
113
+ base_url = "https://all.chatfire.cn/openrouter/v1"
114
+ api_key = os.getenv("OPENROUTER_API_KEY")
115
+
116
+ request = ImageRequest(
117
+ # model="google/gemini-2.5-flash-image-preview:free",
118
+ model="google/gemini-2.5-flash-image-preview:free-hd",
119
+
120
+ # model="gemini-2.5-flash-image-preview",
121
+
122
+ prompt="带个墨镜",
123
+ # image=["https://oss.ffire.cc/files/kling_watermark.png"],
124
+ )
125
+
126
+ r = arun(
127
+ generate(
128
+ request, base_url=base_url, api_key=api_key
129
+ )
130
+ )
@@ -8,4 +8,3 @@
8
8
  # @Software : PyCharm
9
9
  # @Description :
10
10
 
11
- from meutils.pipe import *
@@ -153,7 +153,7 @@ async def make_request_for_baidu(payload, token: Optional[str] = None, response_
153
153
  raise Exception(f"NO WATERMARK FOUND: {data}") #############
154
154
 
155
155
  if response_format == "url":
156
- url = await to_url(image_base64, content_type="image/png")
156
+ url = await to_url(image_base64, filename="_hd.png", content_type="image/png")
157
157
 
158
158
  return ImagesResponse(data=[{"url": url}], timings={"inference": time.time() - s})
159
159
  else:
@@ -18,10 +18,14 @@ from meutils.apis.fal.images import generate as fal_generate
18
18
 
19
19
  from meutils.apis.gitee.image_to_3d import generate as image_to_3d_generate
20
20
  from meutils.apis.gitee.openai_images import generate as gitee_images_generate
21
- from meutils.apis.qwen.chat import Completions as QwenCompletions
22
21
  from meutils.apis.volcengine_apis.images import generate as volc_generate
23
22
  from meutils.apis.images.recraft import generate as recraft_generate
24
23
  from meutils.apis.jimeng.images import generate as jimeng_generate
24
+ # from meutils.apis.google.images import generate as google_generate
25
+
26
+ from meutils.apis.qwen.chat import Completions as QwenCompletions
27
+ from meutils.apis.google.chat import Completions as GoogleCompletions
28
+ from meutils.apis.google.images import generate as google_generate
25
29
 
26
30
 
27
31
  async def generate(
@@ -29,20 +33,7 @@ async def generate(
29
33
  api_key: Optional[str] = None,
30
34
  base_url: Optional[str] = None,
31
35
  ):
32
- if base_url: # 优先级最高
33
- data = {
34
- **request.model_dump(exclude_none=True, exclude={"extra_fields", "aspect_ratio"}),
35
- **(request.extra_fields or {})
36
- }
37
- request = ImageRequest(**data)
38
- if request.model.startswith("doubao"):
39
- request.watermark = False
40
- if request.image and isinstance(request.image, list):
41
- request.image = request.image[0]
42
-
43
- data = to_openai_params(request)
44
- client = AsyncClient(api_key=api_key, base_url=base_url)
45
- return await client.images.generate(**data)
36
+ logger.debug(request)
46
37
 
47
38
  if request.model.startswith("fal-ai"): # 主要 request.image
48
39
  return await fal_generate(request, api_key)
@@ -51,12 +42,12 @@ async def generate(
51
42
  request = RecraftImageRequest(**request.model_dump(exclude_none=True))
52
43
  return await recraft_generate(request)
53
44
 
54
- if request.model.startswith(("seededit", "jimeng")): # 即梦
55
- return await jimeng_generate(request)
56
-
57
- if request.model.startswith(("seed", "seededit_v3.0", "byteedit_v2.0")):
45
+ if request.model.startswith(("seed", "seededit_v3.0", "byteedit_v2.0", "i2i_portrait_photo")): # seededit seedream
58
46
  return await volc_generate(request, api_key)
59
47
 
48
+ if request.model.startswith(("jimeng")): # 即梦
49
+ return await jimeng_generate(request)
50
+
60
51
  if request.model in {"Hunyuan3D-2", "Hi3DGen", "Step1X-3D"}:
61
52
  return await image_to_3d_generate(request, api_key)
62
53
 
@@ -68,9 +59,33 @@ async def generate(
68
59
  request.image = request.image[-1]
69
60
  return await QwenCompletions(api_key=api_key).generate(request)
70
61
 
62
+ if request.model.startswith(("gemini",)):
63
+ return await GoogleCompletions(base_url=base_url, api_key=api_key).generate(request)
64
+
65
+ if request.model.startswith(("google/gemini",)): # openrouter
66
+ return await google_generate(request, base_url=base_url, api_key=api_key)
67
+
68
+ # 其他
69
+ data = {
70
+ **request.model_dump(exclude_none=True, exclude={"extra_fields", "aspect_ratio"}),
71
+ **(request.extra_fields or {})
72
+ }
73
+ request = ImageRequest(**data)
74
+ if request.model.startswith("doubao"):
75
+ request.watermark = False
76
+ if request.image and isinstance(request.image, list):
77
+ request.image = request.image[0]
78
+
79
+ data = to_openai_params(request)
80
+ client = AsyncClient(api_key=api_key, base_url=base_url)
81
+ return await client.images.generate(**data)
82
+
71
83
 
72
84
  # "flux.1-krea-dev"
73
85
 
74
86
  if __name__ == '__main__':
75
87
  # arun(generate(ImageRequest(model="flux", prompt="笑起来")))
76
- arun(generate(ImageRequest(model="FLUX_1-Krea-dev", prompt="笑起来")))
88
+ # arun(generate(ImageRequest(model="FLUX_1-Krea-dev", prompt="笑起来")))
89
+
90
+ token = f"""{os.getenv("VOLC_ACCESSKEY")}|{os.getenv("VOLC_SECRETKEY")}"""
91
+ arun(generate(ImageRequest(model="seed", prompt="笑起来"), api_key=token))
@@ -42,7 +42,6 @@ async def generate(request: ImageRequest, token: Optional[str] = None):
42
42
  "req_key": "high_aes_general_v30l_zt2i",
43
43
  # "req_key": "jimeng_high_aes_general_v21_L",
44
44
 
45
- "prompt": request.prompt,
46
45
  "seed": request.seed,
47
46
  "width": 1328,
48
47
  "height": 1328,
@@ -53,17 +52,16 @@ async def generate(request: ImageRequest, token: Optional[str] = None):
53
52
  # "use_rephraser": True
54
53
  }
55
54
 
56
- image, prompt = request.image_and_prompt
57
- width, height = map(int, request.size.split('x'))
58
-
59
- if image:
60
- payload["image_urls"] = [image]
55
+ if request.image_urls:
56
+ payload["image_urls"] = request.image_urls
61
57
  payload["req_key"] = request.model
62
58
  if payload["req_key"] not in {"seededit_v3.0", "byteedit_v2.0"}:
63
59
  payload["req_key"] = "byteedit_v2.0" # "seededit_v3.0" https://www.volcengine.com/docs/85128/1602254
64
60
 
61
+ width, height = map(int, request.size.split('x'))
65
62
  payload['width'] = width
66
63
  payload['height'] = height
64
+ payload['prompt'] = request.prompt
67
65
 
68
66
  if request.response_format == "oss_url":
69
67
  payload["return_url"] = False
@@ -91,21 +89,22 @@ async def generate(request: ImageRequest, token: Optional[str] = None):
91
89
 
92
90
  if __name__ == '__main__':
93
91
  token = f"""{os.getenv("VOLC_ACCESSKEY")}|{os.getenv("VOLC_SECRETKEY")}"""
94
- token = "AKLTOWM5ZTc5ZDFhZWNlNDIzODkwYmZiNjEyNzYwNzE0MTI|T0RCbFpHRTJaRFEyWmpjeE5ERXpNR0ptWlRCaU16WmhPRE0wWVdKa01tTQ=="
95
92
  prompt = """
96
93
  3D魔童哪吒 c4d 搬砖 很开心, 很快乐, 精神抖擞, 背景是数不清的敖丙虚化 视觉冲击力强 大师构图 色彩鲜艳丰富 吸引人 背景用黄金色艺术字写着“搬砖挣钱” 冷暖色对比
97
94
  """
98
95
 
99
- # prompt = """
100
- # https://oss.ffire.cc/files/kling_watermark.png
101
- # 让这个女人带上眼镜 衣服换个颜色
102
- # """
96
+ prompt = """
97
+
98
+ 让这个女人带上眼镜 衣服换个颜色
99
+ """
103
100
 
104
101
  request = ImageRequest(
105
- model="high_aes_general_v30l_zt2i",
102
+ # model="high_aes_general_v30l_zt2i",
103
+ model="seededit_v3.0",
106
104
  prompt=prompt,
107
105
  response_format="url",
108
106
  size="512x1328",
107
+ # image="https://oss.ffire.cc/files/kling_watermark.png"
109
108
  )
110
109
 
111
110
  arun(generate(request, token=token))